package com.demo.api.service.dict.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.demo.api.interceptor.user.AuthUserInfo;
import com.demo.client.mapper.dict.SysDictMapper;
import com.demo.api.service.dict.IDictService;
import com.demo.api.service.user.IUserSystemService;
import com.demo.api.vo.dict.DictReq;
import com.demo.api.vo.dict.DictRes;
import com.demo.client.model.dict.SysDict;
import com.demo.client.model.user.SysUser;
import com.demo.core.enums.OftenEnum;
import com.demo.core.enums.RedisCacheEnum;
import com.demo.core.redis.RedisCache;
import com.demo.core.redis.RedisTableCache;
import com.demo.core.utils.StringUtils;
import com.demo.core.verification.ValidatorTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class DictServiceImpl implements IDictService {

    @Resource
    private SysDictMapper dictMapper;

    @Resource
    private RedisTableCache redisTableCache;

    @Resource
    private RedisCache redisCache;

    @Resource
    private IUserSystemService userSystemService;


    @Override
    public IPage<DictRes.Page> pages(DictReq.Query req, Page<SysDict> page) {
        LambdaQueryWrapper<SysDict> wrapper = this.commonWrapper(req)
                .eq(req.getStatus() != null, SysDict::getStatus, req.getStatus());
        IPage<DictRes.Page> pages = dictMapper.selectPage(page, wrapper).convert(e -> BeanUtil.copyProperties(e, DictRes.Page.class));
        Set<Long> userIds = Stream.concat(
                pages.getRecords().stream().map(SysDict::getCreateUser),
                pages.getRecords().stream().map(SysDict::getUpdateUser))
                .collect(Collectors.toSet());
        Map<Long, String> map = userSystemService.getUsersList(ListUtil.toList(userIds)).stream().collect(Collectors.toMap(SysUser::getId, SysUser::getName));
        pages.getRecords().forEach(e -> {
            e.setCreateName(map.getOrDefault(e.getCreateUser(), "-"));
            e.setCreateName(map.getOrDefault(e.getUpdateUser(), "-"));
        });
        return pages;
    }

    public <T> void settingUserName(T t) {

    }

    @Override
    public List<DictRes.Page> dictList(DictReq.Query req) {
        String key = createKey(req);
        List<DictRes.Page> list = redisCache.getList(key, DictRes.Page.class);
        if (!ValidatorTools.isEmpty(list)) {
            return list;
        }
        LambdaQueryWrapper<SysDict> wrapper = this.commonWrapper(req).eq(SysDict::getStatus, OftenEnum.EnableState.ENABLE.code());
        list = dictMapper.selectList(wrapper).stream().map(e -> BeanUtil.copyProperties(e, DictRes.Page.class)).collect(Collectors.toList());
        if (!ValidatorTools.isEmpty(list)) {
            redisCache.cacheOneDay(JSON.toJSONString(list), key);
        }
        return list;
    }

    public String createKey(DictReq.Query req) {
        return RedisCacheEnum.DICT_LIST.createKey(req.getParentCode(), req.getName(), req.getParentId(), req.getCode());
    }

    public LambdaQueryWrapper<SysDict> commonWrapper(DictReq.Query req) {
        return Wrappers.lambdaQuery(SysDict.class)
                .eq(SysDict::getDelFlag, OftenEnum.DelEnum.NO_DEL.code())
//                .eq(StringUtils.isNotBlank(req.getCode()), SysDict::getCode, req.getCode())
                .and(StringUtils.isNotBlank(req.getCode()), e -> {
                    e.eq(SysDict::getCode, req.getCode()).or().eq(SysDict::getParentCode, req.getCode());
                })
                .eq(StringUtils.isNotBlank(req.getParentCode()), SysDict::getParentCode, req.getParentCode())
                .eq(ObjectUtil.isNotNull(req.getParentId()), SysDict::getParentId, req.getParentId())
                .like(StringUtils.isNotBlank(req.getName()), SysDict::getName, req.getName());
    }

    @Override
    public void create(DictReq.Create create) {
        DictReq.Query query = BeanUtil.copyProperties(create, DictReq.Query.class);
        query.setParentCode(create.getCode());
        String key = createKey(query);
        if (StringUtils.isNotBlank(create.getCode())) {
            ValidatorTools.commonThrow(dictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class)
                    .eq(SysDict::getDelFlag, OftenEnum.DelEnum.NO_DEL.code())
                    .eq(SysDict::getCode, create.getCode())) != null, "该code已存在");

        }
        this.settingParentCode(create);
        SysDict dict = BeanUtil.copyProperties(create, SysDict.class);
        dict.setCreateUser(AuthUserInfo.getUserId());
        ValidatorTools.checkSqlSuccess(dictMapper.insert(dict), "新增字典失败");
        redisCache.del(key);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void update(DictReq.Update update) {
        DictReq.Query query = BeanUtil.copyProperties(update, DictReq.Query.class);
        query.setParentCode(update.getCode());
        String key = createKey(query);
        SysDict dict = redisTableCache.get(SysDict.class, update.getId());
        ValidatorTools.isNullThrow(dict, "该字典不存在");
        this.settingParentCode(BeanUtil.copyProperties(update, DictReq.Create.class));
        if (StringUtils.isNotBlank(update.getCode())) {
            ValidatorTools.commonThrow(dictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class)
                    .eq(SysDict::getDelFlag, OftenEnum.DelEnum.NO_DEL.code())
                    .eq(SysDict::getCode, update.getCode())) != null &&
                    !ObjectUtil.equal(update.getCode(), dict.getCode()), "该code已存在");

        }
        dict = BeanUtil.copyProperties(update, SysDict.class);
        dict.setUpdateUser(AuthUserInfo.getUserId());
        ValidatorTools.checkSqlSuccess(dictMapper.updateById(dict), "修改字典失败");
        redisCache.del(key);
        redisTableCache.remove(SysDict.class, update.getId());
    }

    public void settingParentCode(DictReq.Create create) {
        if (create.getParentId() != null && !ObjectUtil.equal("0", create.getParentId().toString())) {
            SysDict dict = redisTableCache.get(SysDict.class, create.getParentId());
            ValidatorTools.isNullThrow(dict, "不存在的上级字典");
            create.setParentCode(dict.getCode());
        }
    }

    @Override
    public void delDict(Long id){
        SysDict dict = redisTableCache.get(SysDict.class,id);
        ValidatorTools.isNullThrow(dict,"该字典不存在");
        dict.setDelFlag(OftenEnum.DelEnum.YES_DEL.getCode());
        ValidatorTools.checkSqlSuccess(dictMapper.updateById(dict),"删除失败");
    }

}
